package com.itheima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hankcs.algorithm.AhoCorasickDoubleArrayTrie;
import com.itheima.admin.mapper.AdChannelMapper;
import com.itheima.admin.mapper.AdSensitiveMapper;
import com.itheima.admin.pojo.AdChannel;
import com.itheima.admin.pojo.AdSensitive;
import com.itheima.admin.service.WemediaNewsAutoScanService;
import com.itheima.article.dto.ArticleInfoDto;
import com.itheima.article.feign.ApArticleFeign;
import com.itheima.article.pojo.ApArticle;
import com.itheima.article.pojo.ApArticleConfig;
import com.itheima.article.pojo.ApArticleContent;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.util.AliGreenScanner;
import com.itheima.common.vo.ResultVo;
import com.itheima.dfs.feign.DfsFeign;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.feign.WmNewsFeign;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.vo.WmNewsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    private WmNewsFeign wmNewsFeign;

    @Autowired
    private AdSensitiveMapper adSensitiveMapper;

    @Autowired
    private AliGreenScanner aliGreenScanner;

    @Autowired
    private DfsFeign dfsFeign;

    @Autowired
    private ApArticleFeign apArticleFeign;

    @Autowired
    private AdChannelMapper adChannelMapper;

    @Override
    @Transactional
    public void autoScanWemediaNewsById(Integer newsId, String uuid) {
        //1. 通过文章id获取文章信息--远程调用
        ResultVo<WmNews> wmNewsResultVo = wmNewsFeign.getWmNewsById(newsId);
        WmNews wmNews = wmNewsResultVo.getData();

        //参数校验
        if (!wmNewsResultVo.isSuccess()) {
            log.error("【错误】文章自动审核：uuid={},id={} 远程调用查询文章失败", uuid, newsId);
            return;
        }
        if (null == wmNews) {
            log.error("【错误】文章自动审核：uuid={},id={} 远程调用查询不到文章数据", uuid, newsId);
            return;
        }

        //判断状态是否为已提交
        if (wmNews.getStatus() != BusinessConstants.WmNewsConstants.STATUS_SUBMIT) {
            log.error("【错误】文章自动审核：uuid={},id={} 文章状态不正确", uuid, newsId);
            return;
        }
        //2. 抽取文本内容, 包含内容与标题
        String text = getText(wmNews);
        WmNews updatePojo = new WmNews();
        updatePojo.setId(wmNews.getId());

        //3. 敏感词检测
        //获取敏感词列表--这里使用的是敏感词检测工具类
        /*List<AdSensitive> sensitiveList = adSensitiveMapper.selectList(null);

        List<String> stringList = sensitiveList.stream().map(AdSensitive::getSensitives).collect(Collectors.toList());
        SensitiveWordUtil.initMap(stringList);
        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(text);*/

        //这里使用双向字典表
        boolean testResult = sensitiveWordCheck(text);


        if (testResult) {
            log.info("文章自动审核：uuid={},id={} 文章内容包含敏感词", uuid, newsId);
            updatePojo.setReason("文章包含敏感词！");
        } else {

        }
        //4. 文本反垃圾审核 调用aliyun工具
        try {
            Map<String, String> scanResult = aliGreenScanner.greenTextScan(text);
            if (null == scanResult) {
                log.error("【错误】文章自动审核：uuid={},id={} 调用aliyun文本反垃圾出错", uuid, newsId);
                return;
            }

            if (BusinessConstants.ScanConstants.PASS.equals(scanResult.get("suggestion"))) {
                //5. 提取图片内容
                List<String> imageList = getImageList(wmNews);
                //5.1 远程调用下载图片
                if(!CollectionUtils.isEmpty(imageList)){
                    ResultVo<List<byte[]>> downloadList = dfsFeign.download(imageList);
                    List<byte[]> imageDataList = downloadList.getData();

                    if(!downloadList.isSuccess() || CollectionUtils.isEmpty(imageDataList)){
                        log.error("【错误】文章自动审核：uuid={},id={} 远程调用下载文章图片失败",uuid,newsId);
                        return;
                    }
                    //6. 图片反垃圾审核 调用aliyun工具
                    scanResult = aliGreenScanner.imageScan(imageDataList);
                    if(null == scanResult){
                        log.error("【错误】文章自动审核：uuid={},id={} 调用aliyun图片审核失败",uuid,newsId);
                        return;
                    }
                }
            }
            //审核结果解析
            String result = scanResult.get("suggestion");
            switch (result){
                case BusinessConstants.ScanConstants.PASS:
                    //这里是判断是否有发布时间，修改状态为8(待发布)或者9(已发布)
                    /*if(null != updatePojo.getPublishTime()){
                        updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_PASS);
                    }else {
                        updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_PUBLISHED);
                    }*/
                    updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_PASS);
                    break;
                case BusinessConstants.ScanConstants.REVIEW:
                    updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL);
                    break;
                case BusinessConstants.ScanConstants.BLOCK:
                    updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
                    break;
                default:
                    log.error("【错误】文章自动审核：uuid={},id={} 调用aliyun安全内容审核结果不正常",uuid,newsId);
                    return;
            }

        } catch (Exception e) {
            log.error("【错误】文章自动审核：uuid={},id={} 调用阿里反垃圾失败", uuid, newsId);
            return;
        }

        //7. 更新文章审核状态
        //需要设置文章id，不然就会生成新的文章
        updatePojo.setId(newsId.longValue());
        log.info("文章自动审核结果：uuid={},id={},status={}",uuid,newsId, updatePojo.getStatus());
        ResultVo<WmNews> resultVo = wmNewsFeign.update(updatePojo);

        if(resultVo.isSuccess()){
            log.info("文章自动审核结果更新成功：uuid={},id={},status={}",uuid,newsId, updatePojo.getStatus());
        }else{
            log.error("文章自动审核结果更新失败：uuid={},id={},status={}",uuid,newsId, updatePojo.getStatus());
        }

    }

    /**
     * 同步文章数据
     *
     * @param wmNewsVo
     * @return
     */
    @Override
    public boolean syncArticleInfo(WmNewsVo wmNewsVo) {
        //构建articleInfoDto
        ArticleInfoDto dto = new ArticleInfoDto();
        //构建文章信息apArticle
        ApArticle apArticle = buildApArticle(wmNewsVo);
        dto.setApArticle(apArticle);

        //构建文章内容对象apArticleContent
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setContent(wmNewsVo.getContent());
        dto.setApArticleContent(apArticleContent);

        //构建文章配置对象
        ApArticleConfig apArticleConfig = new ApArticleConfig();
        apArticleConfig.setIsDown(0);
        apArticleConfig.setIsDelete(0);
        apArticleConfig.setIsForward(1);
        apArticleConfig.setIsComment(1);

        dto.setApArticleConfig(apArticleConfig);

        //自媒体用户
        dto.setWmUserId(wmNewsVo.getUserId());
        //app用户id 作者
        dto.setApUserId(wmNewsVo.getApUserId());
        //自媒体文章id(更新状态)
        dto.setWmNewsId(wmNewsVo.getId());

        //远程调用文章微服务保存文章信息
        ResultVo resultVo = apArticleFeign.saveArticleInfo(dto);

        return resultVo.isSuccess();
    }

    /**
     * 构建文章对象
     * @param wmNewsVo
     * @return
     */
    private ApArticle buildApArticle(WmNewsVo wmNewsVo) {
        ApArticle apArticle = new ApArticle();

        //复制属性
        BeanUtils.copyProperties(wmNewsVo,apArticle);
        //需要把旧有的文章id传过去
        apArticle.setId(wmNewsVo.getArticleId());
        //作者id
        apArticle.setAuthorId(wmNewsVo.getApUserId());

        //作者名称
        apArticle.setAuthorName(wmNewsVo.getAuthorName());
        //通过频道id查询频道名称
        Integer channelId = wmNewsVo.getChannelId();
        AdChannel adChannel = adChannelMapper.selectById(channelId);
        apArticle.setChannelName(adChannel.getName());

        //布局
        apArticle.setLayout(wmNewsVo.getType());
        apArticle.setFlag(0);//普通文章
        apArticle.setLikes(0);
        apArticle.setCollection(0);
        apArticle.setComment(0);
        apArticle.setViews(0);
        apArticle.setProvinceId(0);
        apArticle.setCityId(0);
        apArticle.setCountyId(0);
        apArticle.setSyncStatus(0);
        return apArticle;
    }

    /**
     * 获取图片
     * @param wmNews
     * @return
     */
    private List<String> getImageList(WmNews wmNews) {
        List<WmNewsContentNodeDto> contentList = JSON.parseArray(wmNews.getContent(), WmNewsContentNodeDto.class);
        List<String> imageList = contentList.stream().filter(node ->
                BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(node.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());

        if(StringUtils.isNotEmpty(wmNews.getImages())){
            //图片在数据库中是以逗号分隔
            String[] images = wmNews.getImages().split(",");
            Collections.addAll(imageList,images);
        }
        return imageList;
    }

    /**
     * 敏感词检测
     * @param text
     * @return
     */
    private boolean sensitiveWordCheck(String text) {
        //获取数据库中的敏感词信息
        List<AdSensitive> sensitiveList = adSensitiveMapper.selectList(null);

        if (CollectionUtils.isEmpty(sensitiveList)){
            return false;
        }

        //转换成map
        Map<String, String> map = sensitiveList.stream().collect(Collectors.toMap(AdSensitive::getSensitives, AdSensitive::getSensitives));

        //构建字典树
        AhoCorasickDoubleArrayTrie<String> trie = new AhoCorasickDoubleArrayTrie<>();
        trie.build(map);

        //检测并返回，为空则无敏感词
        return trie.findFirst(text) != null;
    }

    /**
     * 抽取文本内容
     *
     * @param wmNews
     * @return
     */
    private String getText(WmNews wmNews) {
        List<WmNewsContentNodeDto> contentNodeDtos = JSON.parseArray(wmNews.getContent(), WmNewsContentNodeDto.class);
        //提取type=text中的value
        List<String> contents = contentNodeDtos.stream().filter(node ->
                BusinessConstants.WmNewsConstants.CONTENT_TEXT.equals(node.getType()))
                .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());

        //添加标题
        contents.add(wmNews.getTitle());
        //以逗号分割拼接
        String text = String.join(",", contents);
        return text;
    }


}
